# -*- coding: utf-8 -*-

import sys
import os
import wx.aui
import gettext
import re

import libs.config
import libs.texttab
import libs.misc

gettext.install(u"messages", u"language", unicode=True)

class MainFrame(wx.Frame):    
    def CreateIDs(self):
        self.ID_MENU_FILE_NEW = wx.NewId()
        self.ID_MENU_FILE_OPEN = wx.NewId()
        self.ID_MENU_FILE_SAVE = wx.NewId()
        self.ID_MENU_FILE_SAVEAS = wx.NewId()
        self.ID_MENU_FILE_EXIT = wx.NewId()
        self.ID_MENU_VIEW_TOOLBAR = wx.NewId()
        self.ID_MENU_VIEW_WHITESPACE = wx.NewId()
        self.ID_MENU_HELP_ABOUT = wx.NewId()
        self.ID_MENU_TOOLBAR_NEW = wx.NewId()
        self.ID_MENU_TOOLBAR_OPEN = wx.NewId()
        self.ID_MENU_TOOLBAR_SAVE = wx.NewId()
        self.ID_MENU_TOOLBAR_SAVEAS = wx.NewId()
        self.ID_MENU_EDIT_ENCODING = wx.NewId()
        self.ID_MENU_EDIT_ENCODING_UTF8 = wx.NewId()
        self.ID_MENU_EDIT_ENCODING_CP1251 = wx.NewId()
        self.ID_MENU_EDIT_EOL = wx.NewId()
        self.ID_MENU_EDIT_EOL_CR = wx.NewId()
        self.ID_MENU_EDIT_EOL_LF = wx.NewId()
        self.ID_MENU_EDIT_EOL_CRLF = wx.NewId()

    def __init__(self, parent):
        sys.stdout = sys.stderr = libs.misc.LogOutput(u"log.txt")
        self.settings = wx.GetApp().GetSettings()
#       Окно
        self.CreateIDs()
        wx.Frame.__init__(self, parent, -1, u"pyCoder v0.2 alpha", wx.DefaultPosition, size=(600, 500), style=wx.DEFAULT_FRAME_STYLE)
        self.Centre()
        icon = wx.Bitmap(u"icons/main.png")
        self.SetIcon(wx.IconFromBitmap(icon))

#       Меню
        menuBar = wx.MenuBar()
#       "Файл"
        menu_file = wx.Menu()
        menu_file.Append(self.ID_MENU_FILE_NEW, _(u"New"))
        menu_file.Append(self.ID_MENU_FILE_OPEN, _(u"Open..."))
        menu_file.Append(self.ID_MENU_FILE_SAVE, _(u"Save"))
        menu_file.Append(self.ID_MENU_FILE_SAVEAS, _(u"Save as..."))
        menu_file.AppendSeparator()
        menu_file.Append(self.ID_MENU_FILE_EXIT,  _(u"Exit"))
        menuBar.Append(menu_file, _(u"File"))
#       "Правка"
        menu_edit = wx.Menu()
        menuBar.Append(menu_edit, _(u"Edit"))
        menu_edit_encoding = wx.Menu()
        menu_edit_encoding.Append(self.ID_MENU_EDIT_ENCODING_UTF8,  _(u"UTF-8"))
        menu_edit_encoding.Append(self.ID_MENU_EDIT_ENCODING_CP1251,  _(u"CP1251"))
        menu_edit.AppendMenu(self.ID_MENU_EDIT_ENCODING, _(u"Encoding"), menu_edit_encoding)
        menu_edit_eol = wx.Menu()
        menu_edit_eol.Append(self.ID_MENU_EDIT_EOL_CR,  _(u"CR (Mac)"))
        menu_edit_eol.Append(self.ID_MENU_EDIT_EOL_LF,  _(u"LF (UNIX)"))
        menu_edit_eol.Append(self.ID_MENU_EDIT_EOL_CRLF,  _(u"CRLF (DOS)"))
        menu_edit.AppendMenu(self.ID_MENU_EDIT_EOL, _(u"EOL"), menu_edit_eol)
#       "Вид"
        menu_view = wx.Menu()
        self.toggleToolbarMenu = menu_view.Append(self.ID_MENU_VIEW_TOOLBAR, _(u"Show toolbar"), kind=wx.ITEM_CHECK)
        self.toggleToolbarMenu.Check()
        menu_view.AppendSeparator()
        menu_view.Append(self.ID_MENU_VIEW_WHITESPACE, _(u"Show whitespaces and tabs"), kind=wx.ITEM_CHECK)
        menuBar.Append(menu_view, _(u"View"))
#       "Справка"
        menu_help = wx.Menu()
        menu_help.Append(self.ID_MENU_HELP_ABOUT, _(u"About..."))
        menuBar.Append(menu_help, _(u"Help..."))
        self.SetMenuBar(menuBar)

#       Тулбар
        self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT)
        self.toolbar.SetToolBitmapSize((16,16))
        icon_newfile = wx.Bitmap(os.path.join(u"icons", u"newfile.png"))
        icon_openfile = wx.Bitmap(os.path.join(u"icons", u"openfile.png"))
        icon_savefile = wx.Bitmap(os.path.join(u"icons", u"savefile.png"))
        icon_savefileas = wx.Bitmap(os.path.join(u"icons", u"savefileas.png"))
        self.toolbar.AddLabelTool(self.ID_MENU_TOOLBAR_NEW, _(u"New"), icon_newfile, shortHelp = _(u"Create new file..."))
        self.toolbar.AddLabelTool(self.ID_MENU_TOOLBAR_OPEN, _(u"Open..."), icon_openfile, shortHelp = _(u"Open existing file..."))
        self.toolbar.AddLabelTool(self.ID_MENU_TOOLBAR_SAVE, _(u"Save"), icon_savefile, shortHelp = _(u"Save current file..."))
        self.toolbar.AddLabelTool(self.ID_MENU_TOOLBAR_SAVEAS, _(u"Save as..."), icon_savefileas, shortHelp = _(u"Save current file..."))
        self.toolbar.AddSeparator()
        self.toolbar.Realize()
        if not self.settings[u"ShowToolbar"]:
            self.toggleToolbarMenu.Check(False)
            self.toolbar.Hide()
            self.SendSizeEvent()
        else:
            self.toggleToolbarMenu.Check(True)

#       Статусбар
        self.statusBar = self.CreateStatusBar()
        self.statusBar.SetFieldsCount(6)
        self.statusBar.SetStatusWidths([-1, -1, -1, -1, -1, -1])
        self.statusBar.SetStatusText(_(u"Plain text"), 0)
        self.statusBar.SetStatusText(u"Pos: 0, 0", 1)
        self.statusBar.SetStatusText(u"Lines: 0", 2)
        self.statusBar.SetStatusText(u"Chars: 0", 3)
        self.statusBar.SetStatusText(u"UTF-8", 4)
        self.statusBar.SetStatusText(self.settings["DefaultEOLMode"], 5)
        
#       Вкладки
        self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.tabs = wx.aui.AuiNotebook(self)
        self.CreateNewTab()

#       Привязки
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_MENU, self.OnNewFile, id = self.ID_MENU_FILE_NEW)
        self.Bind(wx.EVT_MENU, self.OnFileOpen, id = self.ID_MENU_FILE_OPEN)
        self.Bind(wx.EVT_MENU, lambda event: self.OnFileSave(False), id = self.ID_MENU_FILE_SAVE)
        self.Bind(wx.EVT_MENU, lambda event: self.OnFileSave(True), id = self.ID_MENU_FILE_SAVEAS)
        self.Bind(wx.EVT_MENU, self.OnClose, id = self.ID_MENU_FILE_EXIT)
        self.Bind(wx.EVT_MENU, lambda event: self.OnEncodingChange(u"utf-8"), id = self.ID_MENU_EDIT_ENCODING_UTF8)
        self.Bind(wx.EVT_MENU, lambda event: self.OnEncodingChange(u"cp1251"), id = self.ID_MENU_EDIT_ENCODING_CP1251)
        self.Bind(wx.EVT_MENU, lambda event: self.OnEOLChange(u"CR"), id = self.ID_MENU_EDIT_EOL_CR)
        self.Bind(wx.EVT_MENU, lambda event: self.OnEOLChange(u"LF"), id = self.ID_MENU_EDIT_EOL_LF)
        self.Bind(wx.EVT_MENU, lambda event: self.OnEOLChange(u"CRLF"), id = self.ID_MENU_EDIT_EOL_CRLF)
        self.Bind(wx.EVT_MENU, self.ToggleToolbar, id = self.ID_MENU_VIEW_TOOLBAR)
        self.Bind(wx.EVT_MENU, self.OnAbout, id = self.ID_MENU_HELP_ABOUT)
        self.Bind(wx.EVT_MENU, self.OnNewFile, id = self.ID_MENU_TOOLBAR_NEW)
        self.Bind(wx.EVT_MENU, self.OnFileOpen, id = self.ID_MENU_TOOLBAR_OPEN)
        self.Bind(wx.EVT_MENU, lambda event: self.OnFileSave(False), id = self.ID_MENU_TOOLBAR_SAVE)
        self.Bind(wx.EVT_MENU, lambda event: self.OnFileSave(True), id = self.ID_MENU_TOOLBAR_SAVEAS)
        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnTabChange)
        self.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnCurPosChange)

    def GetCurrentTab(self):
        return self.tabs.GetPage(self.tabs.GetSelection())

    def ToggleToolbar(self, event):
        if self.toggleToolbarMenu.IsChecked():
            self.toolbar.Show()
            self.SendSizeEvent()
            self.settings[u"ShowToolbar"] = True
        else:
            self.toolbar.Hide()
            self.SendSizeEvent()
            self.settings[u"ShowToolbar"] = False

    def CreateNewTab(self, tabName = _(u"Untitled")):
        tab = libs.texttab.TextTab(self.tabs)
        self.tabs.AddPage(tab, tabName, True)

    def OnFileOpen(self, event):
        encoding = u"cp1251"
        dialog = wx.FileDialog(self, message=_(u"Choose a file..."), wildcard = "All files (*.*)|*.*|Plain text (*.txt)|*.txt|XML (*.xml)|*.xml", style = wx.OPEN)
#       Открытие
        if dialog.ShowModal() == wx.ID_OK:
            self.CreateNewTab(dialog.GetFilename())
            tab = self.GetCurrentTab()
            tab.filename = dialog.GetPath()
            file = open(dialog.GetPath(), u"rb")
#           Определение формата конца строки
            line_ending = file.readline()[-2:].encode("hex")
            if line_ending == u"0d0a":
                tab.SetLineFormat(u"CRLF")
            elif line_ending[-2:] == u"0d":
                tab.SetLineFormat(u"CR")
            else:
                tab.SetLineFormat(u"LF")

            self.statusBar.SetStatusText(tab.lineformat, 5)
            file.seek(0)

            header = file.read(4)
            if u"efbbbf" == header[:3].encode(u"hex"):
                encoding = u"utf-8"
                file.seek(3)
            elif u"feff" == header[:2].encode(u"hex"):
                encoding = u"utf_16_be"
                file.seek(2)
            elif u"fffe" == header[:2].encode(u"hex"):
                encoding = u"utf_16_le"
                file.seek(2)
            elif u"0000feff" == header.encode(u"hex"):
                encoding = u"utf_32_be"
            elif u"fffe0000" == header.encode(u"hex"):
                encoding = u"utf_32_le"
            else:
                file.seek(0)
            tab.encoding = encoding
            self.statusBar.SetStatusText(libs.misc.ConvertEncodingName(encoding), 4)

#           Чтение
            for line in file.xreadlines():
                tab.AppendText(line.decode(encoding))
            file.close()
        dialog.Destroy()

    def OnFileSave(self, SaveAs = False):
        filePath = ""
        fileName = self.tabs.GetPageText(self.tabs.GetSelection())
        tab = self.GetCurrentTab()
        if SaveAs == False:
            if tab.filename == "":
                dialog = wx.FileDialog(self, message=_(u"Choose a file..."), style = wx.SAVE)
                if dialog.ShowModal() == wx.ID_OK:
                    fileName = dialog.GetFilename()
                    filePath = dialog.GetPath()
                dialog.Destroy()
            else:
                filePath = tab.filename
        else:
            dialog = wx.FileDialog(self, message=_(u"Choose a file..."), style = wx.SAVE)
            if dialog.ShowModal() == wx.ID_OK:
                fileName = dialog.GetFilename()
                filePath = dialog.GetPath()
            dialog.Destroy()
        
        if filePath <> "": 
            file = open(filePath, u"wb")
            if tab.encoding == "utf-8":
#               Writing BOM
                file.write(u"efbbbf".decode(u"hex"))
            file.writelines(tab.GetText().encode(tab.encoding))
            file.close()
            self.tabs.SetPageText(self.tabs.GetSelection(), fileName)
        
    def OnEOLChange(self, ConvertTo):
        tab = self.GetCurrentTab()
        
        if tab.lineformat == u"CRLF":
            srcEOL = u"\r\n"
        elif tab.lineformat == u"CR":
            srcEOL = u"\r"
        else:
            srcEOL = u"\n"
            
        if ConvertTo == u"CRLF":
            EOL = u"\r\n"
        elif ConvertTo == u"CR":
            EOL = u"\r"
        else:
            EOL = u"\n"
            
        tab.SetLineFormat(ConvertTo)
        tab.SetText(re.sub(srcEOL, EOL, tab.GetText()))
        self.statusBar.SetStatusText(tab.lineformat, 5)
        
    def OnEncodingChange(self, ConvertTo):
        tab = self.GetCurrentTab()
        tab.SetEncoding(ConvertTo)
        self.statusBar.SetStatusText(libs.misc.ConvertEncodingName(tab.encoding), 4)

    def OnCurPosChange(self, event):
        tab = self.GetCurrentTab()
        self.statusBar.SetStatusText(u"Pos: " + str(tab.GetLinePos() + 1) + u", " + str(tab.GetColPos()), 1)
        self.statusBar.SetStatusText(u"Lines: " + str(tab.GetTotalLines()), 2)
        self.statusBar.SetStatusText(u"Chars: " + str(tab.GetTotalChars()), 3)

    def OnTabChange(self, event): 
        tab = self.GetCurrentTab()
        self.statusBar.SetStatusText(u"Pos: " + str(tab.GetLinePos() + 1) + u", " + str(tab.GetColPos()), 1)
        self.statusBar.SetStatusText(u"Lines: " + str(tab.GetTotalLines()), 2)
        self.statusBar.SetStatusText(u"Chars: " + str(tab.GetTotalChars()), 3)
        self.statusBar.SetStatusText(libs.misc.ConvertEncodingName(tab.encoding), 4)
        self.statusBar.SetStatusText(tab.lineformat, 5)

    def OnAbout(self, event):
        dlg = wx.MessageDialog(None, _(u"Copyright © 2010 stryaponoff"), _(u"About..."), wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnClose(self, event):
        libs.config.SaveConfig(self.settings, u"config.xml")
        self.Destroy()

    def OnNewFile(self, event):
        self.CreateNewTab()